/**
 * 解码方法
 *
 * 一条包含字母 A-Z 的消息通过以下映射进行了 编码 ：
 * "1" -> 'A'
 * "2" -> 'B'
 * ...
 * "25" -> 'Y'
 * "26" -> 'Z'
 * 然而，在 解码 已编码的消息时，你意识到有许多不同的方式来解码，因为有些编码被包含在其它编码当中（"2" 和 "5" 与 "25"）。
 * 例如，"11106" 可以映射为：
 * "AAJF" ，将消息分组为 (1, 1, 10, 6)
 * "KJF" ，将消息分组为 (11, 10, 6)
 * 消息不能分组为  (1, 11, 06) ，因为 "06" 不是一个合法编码（只有 "6" 是合法的）。
 * 注意，可能存在无法解码的字符串。
 * 给你一个只含数字的 非空 字符串 s ，请计算并返回 解码 方法的 总数 。如果没有合法的方式解码整个字符串，返回 0。
 * 题目数据保证答案肯定是一个 32 位 的整数。
 *
 * 示例 1：
 * 输入：s = "12"
 * 输出：2
 * 解释：它可以解码为 "AB"（1 2）或者 "L"（12）。
 *
 * 示例 2：
 * 输入：s = "226"
 * 输出：3
 * 解释：它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
 *
 * 示例 3：
 * 输入：s = "06"
 * 输出：0
 * 解释："06" 无法映射到 "F" ，因为存在前导零（"6" 和 "06" 并不等价）。
 *
 * 提示：
 * 1 <= s.length <= 100
 * s 只包含数字，并且可能包含前导零。
 */

/**
 * 看到字符串我们要想到动态规划, 我们定义 dp 数组
 * dp[i] : 从 0 ~ i - 1 位置的情况数量
 * dp[i] = dp[i - 1]
 * 要是前面的可以组合, 再加上 dp[i - 2]
 * 时间复杂度 : O(n)
 * 空间复杂度 : O(n)
 */

public class Main {
    public int numDecodings(String ss) {

        // 字符转字符数组
        char[] s = ss.toCharArray();
        int n = s.length;

        // dp 数组
        int[] dp = new int[n + 1];

        // 初始化, 为第一个字符铺垫
        dp[0] = 1;

        // 循环
        for (int i = 1; i <= n; i++) {

            // 先判断这个位置是否为 '0'
            if (s[i - 1] != '0') {

                // 不是零, 说明可以单独成一组, 加上前面的数量
                dp[i] = dp[i - 1];
            }

            // 因为这个位置的数字还可以和前面的数字组合
            // 判断组合
            // 当 i > 1 的时候
            if (i > 1) {

                // 判断这个组合的大小, 因为要想组合在 26 以内, 还要前面一个数不能是 0
                // 所以也要大于 10
                int tmp = (s[i - 2] - '0') * 10 + (s[i - 1] - '0');

                if (tmp <= 26 && tmp >= 10) {

                    // 成功组合, 加上前面的情况
                    dp[i] += dp[i - 2];
                }
            }
        }

        // 返回结果
        return dp[n];
    }
}